using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using TabControlLib.Data;
using TabControlLib.Tools;

namespace TabControlLib.Controls
{
    public class TabPanel : Panel
    {
        private int _itemCount;

        internal bool CanUpdate = true;

        internal Dictionary<int, TabItem> ItemDic = new();

        public static readonly DependencyPropertyKey FluidMoveDurationPropertyKey =
            DependencyProperty.RegisterReadOnly("FluidMoveDuration", typeof(Duration), typeof(TabPanel),
                new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(0))));

        public static readonly DependencyProperty FluidMoveDurationProperty =
            FluidMoveDurationPropertyKey.DependencyProperty;

        public Duration FluidMoveDuration
        {
            get => (Duration)GetValue(FluidMoveDurationProperty);
            set => SetValue(FluidMoveDurationProperty, value);
        }

        public static readonly DependencyProperty IsTabFillEnabledProperty = DependencyProperty.Register(
            nameof(IsTabFillEnabled), typeof(bool), typeof(TabPanel), new PropertyMetadata(ValueBoxes.FalseBox));

        public bool IsTabFillEnabled
        {
            get => (bool)GetValue(IsTabFillEnabledProperty);
            set => SetValue(IsTabFillEnabledProperty, ValueBoxes.BooleanBox(value));
        }

        public static readonly DependencyProperty TabItemWidthProperty = DependencyProperty.Register(
            nameof(TabItemWidth), typeof(double), typeof(TabPanel), new PropertyMetadata(200.0));

        public double TabItemWidth
        {
            get => (double)GetValue(TabItemWidthProperty);
            set => SetValue(TabItemWidthProperty, value);
        }

        public static readonly DependencyProperty TabItemHeightProperty = DependencyProperty.Register(
            nameof(TabItemHeight), typeof(double), typeof(TabPanel), new PropertyMetadata(30.0));

        public double TabItemHeight
        {
            get => (double)GetValue(TabItemHeightProperty);
            set => SetValue(TabItemHeightProperty, value);
        }

        internal bool ForceUpdate;

        private Size _oldSize;

        private bool _isLoaded;

        protected override Size MeasureOverride(Size constraint)
        {
            if ((_itemCount == InternalChildren.Count || !CanUpdate) && !ForceUpdate && !IsTabFillEnabled) return _oldSize;
            constraint.Height = TabItemHeight;
            _itemCount = InternalChildren.Count;

            var size = new Size();

            ItemDic.Clear();

            var count = InternalChildren.Count;
            if (count == 0)
            {
                _oldSize = new Size();
                return _oldSize;
            }
            constraint.Width += InternalChildren.Count;

            var itemWidth = .0;
            var arr = new int[count];

            if (!IsTabFillEnabled)
            {
                itemWidth = TabItemWidth;
            }
            else
            {
                if (TemplatedParent is TabControl tabControl)
                {
                    arr = DivideInt2Arr((int)tabControl.ActualWidth + InternalChildren.Count, count);
                }
            }

            for (var index = 0; index < count; index++)
            {
                if (IsTabFillEnabled)
                {
                    itemWidth = arr[index];
                }
                if (InternalChildren[index] is TabItem tabItem)
                {
                    tabItem.RenderTransform = new TranslateTransform();
                    tabItem.MaxWidth = itemWidth;
                    var rect = new Rect
                    {
                        X = size.Width - tabItem.BorderThickness.Left,
                        Width = itemWidth,
                        Height = TabItemHeight
                    };
                    tabItem.Arrange(rect);
                    tabItem.ItemWidth = itemWidth - tabItem.BorderThickness.Left;
                    tabItem.CurrentIndex = index;
                    tabItem.TargetOffsetX = 0;
                    ItemDic[index] = tabItem;
                    size.Width += tabItem.ItemWidth;
                }
            }
            size.Height = constraint.Height;
            _oldSize = size;
            return _oldSize;
        }

        private int[] DivideInt2Arr(int total, int count)
        {
            var arr = new int[count];
            var average = total / count;
            var rest = total % count;

            for (var i = 0; i < count; i++)
            {
                arr[i] = average;
                if (i < rest)
                {
                    arr[i]++;
                }
            }

            return arr;
        }

        public TabPanel()
        {
            Loaded += (s, e) =>
            {
                if (_isLoaded) return;
                ForceUpdate = true;
                Measure(new Size(DesiredSize.Width, ActualHeight));
                ForceUpdate = false;
                foreach (var item in ItemDic.Values)
                {
                    item.TabPanel = this;
                }
                _isLoaded = true;
            };
        }
    }
}
